#!/usr/bin/python 
'''
symbide is a GUI for sympy, an open source CAS
'''
#TODO: rewrite COM

""" 
#TODO: write tests for Com
#TODO: expose more functions for use from command line

import __init__

import sys, os.path
from xml.dom import minidom
from xml.sax.saxutils import unescape

from symbide import parsers as _parsers
from symbide import settings as _settings
from symbide import executor as _executor

def totext(dom):
    '''
    Converts a DOM in a as nice as possible text representation.
    
    Therefor all plots are deleted and on the right places
    newlines are enforced.
    '''
    
    plot = dom.getElementsByTagName('symbide_plot')
    for p in plot:
        p.parentNode.removeChild(p)
    xml = dom.toxml()
    def subst(tag):
        if tag.group()[1:-1] in ('/input', '/output', '/cell'):
            return '\n\n'
        if tag.group()=='cell':
            return '\n'
        return ''
    return unescape(_settings.pattern['tag'].sub(subst, xml)).strip('\n')

def todom(*args):
    ''' 
    Returns a complete Symbide DOM with the arguments alternating as inputs
    and outputs.
    
    Arguments can either be strings or DOM representations, but there always
    must be an even number of them.
    '''
    
    assert len(args)%2==0 ,'need even number of arguments!'
    args = list(args)
    rootElement = minidom.Element('worksheet')
    rootElement.setAttribute('title', 'Symbide Worksheet')
    rootElement.setAttribute('xmlns', 'http://code.google.com/p/symbide/')
    while args:
        cell = minidom.Element('cell')
        rootElement.appendChild(cell)
        for n in ('input', 'output'):
            i = args.pop(0)
            if type(i)==str:
                node = minidom.Element(n)
                text = minidom.Document().createTextNode(i)
                node.appendChild(text)
            elif isinstance(i, minidom.Node):
                node = i
            cell.appendChild(node)
    return rootElement
            
def export(DOM, style='', path=''):
    '''
    Transforms a Symbide DOM to xml/xsl or html/css. If no style is given
    a default style is used, if no path is given, a string is returned.
    '''

    if style=='':
        style = 'input_output_colored.css'
    if not os.path.exists(style):
        if os.path.exists(os.path.abspath(style)):
            style = os.path.abspath(style)
        else:
            ext = os.path.splitext(style)[1].strip('.')
            if ext in ('css','xsl'):
                style = os.path.join(_settings.dirs[ext], style)
            assert os.path.exists(style)
    return _parsers['export'].export(DOM, style, path)

def getStylesheets():
    '''
    Returns all available css and xsl stylesheets.
    '''
    
    stylesheets = []
    for mode in ('css', 'xsl'):
        dir = _settings.dirs[mode]
        paths = os.listdir(dir)
        for p in paths:
            longp = os.path.join(dir,p)
            if os.path.isfile(longp) and os.path.splitext(p)[1] in ('.css', '.xsl'):
                stylesheets.append(p)
    return stylesheets
    
def execute(path_in, path_out='print', style='plain'):
    '''
    Executes the file_in and saves, depending on the given arguments,
    appropriate things to file_out.
    
    path_in has to be a string. If the string is an existing path, the file
    is loaded. Otherwise path_in is taken as input.
    
    path_out can be 'print', 'return' or a path. If it is 'print' the Output is written
    to stdout, if it is 'return' the output is returned. Given a path, the output
    will be saved there.
    
    The style determines the format of the output. The following is possible:
        -plain (default), output is plain text
        -symbide, output will be a normal Symbide worksheet xml
        -a path to css or a xsl stylesheet, output will be html or xml
        
    The stylesheet will be searched first in the working directory and afterwards in
    the default stylesheet directory of Symbide.
    Of course, if you give a full qualified path, this one will be taken.
    If the path is not valid, output will be a symbide xml file.
    '''
    
    assert isinstance(path_in, str)
    assert isinstance(path_out, str)
    
    #get the input text
    if os.path.exists(path_in):
            f = open(path_in)
            input = f.read()
            f.close()
            output = _executor.execute(input)
    else:
        input = path_in
        output = _executor.execute(input)
    
    #transform into right output format
    if style=='plain':
        buf = totext(output)
    elif style=='symbide':
        buf = todom(input, output).toxml()
    else:
        if os.path.exists(os.path.abspath(style)):
            buf = export(todom(input, output), os.path.abspath(style), path_out)
            if path_out:
                return
        elif style in getStylesheets():
            buf = export(todom(input, output), style, path_out)
            if path_out:
                return
        else:
            buf = todom(input, output).toxml()
    
    #give back the output to the choosen backend
    if path_out=='print':
        print buf
        return
    if path_out=='return':
        return buf
    f = open(path_out, 'w')
    f.write(buf)
    f.close()
    

#this is for use from command line
if __name__== '__main__':
    #TODO: enable some flags
    args = sys.argv[1:]
        
    if len(args)==1: #single file is printed
        execute(args.pop())
    
    #if more files are given every uneven file is executed and 
    #saved to the next path
    elif len(args)%2==0: 
        while args:
            execute(args.pop(), args.pop())
"""
